package org.common.utils.net.netty.http.core;
import com.esotericsoftware.reflectasm.MethodAccess;
import org.common.utils.net.netty.http.core.annotation.Param;
import org.common.utils.net.netty.http.core.annotation.Path;
import org.common.utils.net.netty.http.exception.HttpPathDuplicateException;
import org.common.utils.tool.ClassTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

/**
 * 路由池
 * @author zhouzhibing
 * @date 2025/11/20 20:14
 */
public class RouterPool {

    private static final Logger log = LoggerFactory.getLogger(RouterPool.class);

    /**
     * 路由信息<路径地址，路由信息>
     */
    private final Map<String , RouteInfo> routeInfoMap = new HashMap<>();

    public RouterPool(String packageName) {
        init(packageName);
    }

    /**
     * 初始化
     * @param packageName 包名
     */
    private void init(String packageName) {
        Set<Class<?>> allClass = ClassTool.getAllClass(packageName);
        try {
            for (Class<?> clazz : allClass) {
                //检查是http路径类
                Path classPath = clazz.getAnnotation(Path.class);
                if(classPath == null) {
                    continue;
                }

                String classPathValue = classPath.value();
                Method[] methods = clazz.getDeclaredMethods();
                Object instance = clazz.newInstance();
                MethodAccess methodAccess = MethodAccess.get(clazz);

                for (Method method : methods) {
                    Path methodPath = method.getAnnotation(Path.class);
                    if(methodPath == null) {
                        continue;
                    }

                    List<MethodParam> methodParams = getMethodParams(method);
                    String methodPathValue = methodPath.value();
                    String originalPath = classPathValue + methodPathValue;
                    List<String> pathParamNames = null;
                    int pathParamStartIndex = originalPath.indexOf("/{");
                    int endIndex = originalPath.length();

                    //存在路径参数
                    if(pathParamStartIndex > 0) {
                        endIndex = pathParamStartIndex;
                        pathParamNames = getPathParams(originalPath);
                    }
                    String path = originalPath.substring(0 , endIndex);

                    //检查路径是否重复
                    if(routeInfoMap.containsKey(path)) {
                        throw new HttpPathDuplicateException(path);
                    }

                    RouteInfo routeInfo = new RouteInfo(instance , methodAccess, method , path , methodParams , pathParamNames);
                    routeInfoMap.put(path , routeInfo);
                }
            }
        } catch (Exception e) {
            log.error("init error" , e);
        }
    }

    public List<MethodParam> getMethodParams(Method method) {
        int parameterCount = method.getParameterCount();
        List<MethodParam> methodParams = new ArrayList<>(parameterCount);

        if(parameterCount > 0) {
            for (Parameter parameter : method.getParameters()) {
                Param annotation = parameter.getAnnotation(Param.class);
                if(annotation != null) {
                    String paramName = annotation.value();
                    MethodParam methodParam = new MethodParam(paramName , parameter.getType());
                    methodParams.add(methodParam);
                }
            }
        }
//        if(parameterCount != methodParams.size()) {
//            throw new HttpMethodParamException(method);
//        }
        return methodParams;
    }

    /**
     * 获取路径参数
     * @param originalPath 路径
     * @return 路径参数
     */
    private List<String> getPathParams(String originalPath) {
        List<String> pathParams = new ArrayList<>(4);
        String[] split = originalPath.split("/");
        for (String path : split) {
            if(path.startsWith("{") && path.endsWith("}")) {
                String pathParamName = path.substring(1 , path.length() - 1);
                pathParams.add(pathParamName);
            }
        }
        return pathParams;
    }

    /**
     * 获取路由信息
     * @param path 路径
     * @return 路由信息
     */
    public RouteInfo getRouteInfo(String path) {
        RouteInfo routeInfo = routeInfoMap.get(path);
        if(routeInfo == null) {
            for (RouteInfo info : routeInfoMap.values()) {
                if(path.startsWith(info.getPath())) {
                    routeInfo = info;
                    break;
                }
            }
        }
        return routeInfo;
    }
}
